#pragma once

#include <types.h>
#include <time.h>
#include <event.h>

typedef enum
{
    VMO_ANONYM = 0,     /* lazy allocation */
    VMO_DATA = 1,       /* immediate allocation */
    VMO_FILE = 2,       /* file backed */
    VMO_SHM = 3,        /* shared memory */
    VMO_USER_PAGER = 4, /* support user pager */
    VMO_DEVICE = 5,     /* memory mapped device registers */
} vmo_type_t;

#define PROT_READ 0x1  /* Page can be read.  */
#define PROT_WRITE 0x2 /* Page can be written.  */
#define PROT_EXEC 0x4  /* Page can be executed.  */
#define PROT_NONE 0x0  /* Page can not be accessed.  */

typedef s32_t status_t; // for syscall

void usys_console_putc(char c);
size_t usys_console_puts(const char *buf, size_t size);

slot_t usys_slot_copy(slot_t dest, slot_t slot);

slot_t usys_process_create();
void usys_process_exit(int);
slot_t usys_thread_create(slot_t process_slot, void *stack, void *pc, void *arg);
void sys_thread_exit();

slot_t usys_vmo_create(u64_t size, u64_t type);
int usys_vmo_write(slot_t slot, u64_t offset, u64_t user_ptr, u64_t len);
int usys_vmo_read(slot_t slot, u64_t offset, u64_t user_ptr, u64_t len);
void usys_vmo_destory(slot_t slot);

void *usys_vmo_map(slot_t slot, u64_t addr, u64_t prot, u64_t flags);
void *usys_vmo_map_to_process(slot_t vmo_slot, slot_t process_slot, u64_t addr, u64_t prot, u64_t flags);
u64_t usys_register_server(u64_t callback, u64_t max_client);
u64_t usys_register_named_server(const char *name, u64_t callback, u64_t max_client);
u32_t usys_register_client(u32_t server_cap, u64_t vm_config_ptr, u64_t buf_size);
u32_t usys_register_client_by_name(const char *name, u64_t vm_config_ptr, u64_t buf_size);
u64_t usys_ipc_call(u64_t icb, u64_t ipc_msg);
void usys_ipc_return(u64_t ret);

typedef union
{
    s64_t tv64;
} ktime_t;

typedef s64_t kticks_t;
typedef s64_t kduration_t;

static inline s64_t ktime_to_ns(const ktime_t kt)
{
    return ((kt).tv64);
}

static inline kduration_t ms_to_kduration(s64_t ms)
{
    return ms * 1000000L;
}

status_t usys_nanosleep(ktime_t deadline);
status_t usys_clock_get(clockid_t type, ktime_t *time);
ktime_t usys_clock_get_monotonic();
kticks_t usys_ticks_get();
kticks_t usys_ticks_per_second();
ktime_t usys_deadline_after(kduration_t nanoseconds);
void usys_yield();
int usys_futex_wait(u32_t *uaddr, u32_t val);
int usys_futex_wake(u32_t *uaddr);

struct kobj_poll_desc_t
{
    int slot;
    uint32_t signals;
    uint32_t rsignals;
};

void usys_object_wait_many(struct kobj_poll_desc_t *desc, int nr, kduration_t *timeout);
void usys_object_signal(int slot, uint32_t set_mask, uint32_t clear_mask);

u64_t usys_block_read(u8_t *buf, u64_t offset, u64_t count);
u64_t usys_block_write(u8_t *buf, u64_t offset, u64_t count);
u64_t usys_block_capacity();
u64_t usys_block_size();
u64_t usys_block_count();

u64_t usys_framebuffer_create(u64_t addr);
void usys_framebuffer_get_info(uint32_t *width, uint32_t *height, uint32_t *stride);
void usys_framebuffer_present();
int usys_event_create();
int usys_event_read(struct input_event_t *e);

void usys_fifo_write(slot_t slot, unsigned char *buf, unsigned int len);
int usys_fifo_read(slot_t slot, unsigned char *buf, unsigned int len);
int usys_fifo_create(unsigned int size);
void usys_fifo_destory(slot_t slot);